

//#define LEN 128
#include "common2.h"
void func(int arg){//在子进程发出SIGCHLD信号后回收子进程的僵尸
	wait(NULL);
}
int num = 0;
int max;

/************************************************************************/
/*******************       服务器创建函数       *************************/
/************************************************************************/
int main(int argc, const char *argv[])
{ 
	int serverfd,clientfd;//用来记录获得serverfd文件的描述符；服务器的套接字,客户端的套接字;
	struct sockaddr_in serveraddr,clientaddr;//用到scokaddr_in结构体
	socklen_t serverlen = sizeof(serveraddr);
	socklen_t clientlen = sizeof(clientaddr);
	int relen;
	//线程用
	pid_t pid;
	//结构体
	MSG msg;
	//数据库
	sqlite3 *db;
	
	if(sqlite3_open(PATH_DATA,&db)!=SQLITE_OK)//打开数据库，参数为数据库名字，指针
	{
		printf("%s\n",sqlite3_errmsg(db));
		return -1;
	}
	
	//提醒用户填写正确格式，运行时填写ip和端口号;
	if(argc!=3)
	{
		printf("User:%s <IP> <port>\n",argv[0]);
		return -1;
	}
	
	//socket->填充->绑定->监听->等待连接->数据交互->关闭
	//1.socket
	
	serverfd = socket(AF_INET,SOCK_STREAM,0);  //创建serverfd，获得serverfd文件描述符,socket函数的参数为协议。
	if(serverfd < 0)//创建失败为-1；
	{
		perror("socket");
		return -1;
	}
	printf("serverfd=%d\n",serverfd);
	
	//使用的别人的优化/*优化4： 允许绑定地址快速重用 */
	int b_reuse = 1;
	setsockopt (serverfd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof (int));
	
	
	//2.填充网络类型，端口号，ip地址
	
	serveraddr.sin_family = AF_INET;//ipv4协议
	serveraddr.sin_port = htons(atoi(argv[2]));//端口号
	serveraddr.sin_addr.s_addr = inet_addr(argv[1]);//IP地址
	
	
	//3.绑定
	
	if(bind(serverfd,(struct sockaddr *)&serveraddr,serverlen) < 0)
	//bind函数参数填充1服务器的套接字，2填充的serveraddr的信息，3服务器addr的长度。
	{
		perror("bind");
		return -1;
	}
	
	//4.监听
	
	if(listen(serverfd,10)<0)
	//listen监听函数参数为1服务器套接字，2最大连接个数
	{
		perror("listen");
		return -1;
	}


	signal(SIGCHLD,func);//注册子进程退出的回收僵尸函数
	
/*************************************************************************************/	
	
	

max_find(clientfd,&msg,db);



/*************************************************************************************/	
	//5.等待连接    多客户端多线程
	while(1)//死循环
	{
		if((clientfd=accept(serverfd,(struct sockaddr*)&clientaddr,&serverlen))<0)
		//链接客户端的请求,记录下客户端的套接字。失败小于0
		{
			perror("fail to accept");
			continue;
		}
		printf("clientfd=%d,ClientIP:%s\n",clientfd,inet_ntoa(clientaddr.sin_addr));
		
		pid=fork();//创建线程来了新tcp客户，需要建立一个新的进程来处理收发消息
		if(pid < 0)
		{
			perror("fail to fork");
			continue;
		}
		else if(pid==0) //接收客户端的请求处理过程,此为子进程。
		{
			close(serverfd);//子进程不需要接收客户端连接的sfd，直接关闭
			while(1)
			{
				relen = recv(clientfd,&msg,LEN_SMG, 0); //recv的fd要写accept返回的fd,recv接受客户端数据.
				//不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据.recv函数参数详见word;
				//等待回应
				
				if(relen<=0)/* 客户端断开 relen返回0 recv不再阻塞，需要退出while循环*/
				{	
					printf("client offline\n");
					close(clientfd);//关闭客户端套接字
					exit(1);
				}
				
				switch(msg.type)
				{
					case A:
						adm_lg(clientfd,&msg,db);
						break;
					case B:
						user_lg(clientfd,&msg,db);
						break;
					case C:
						amend_pswd(clientfd,&msg,db);
						break;
					case D:
						user_fd(clientfd,&msg,db);
						break;
					case F:
						
						adm_add(clientfd,&msg,db);
						break;
					case G:
						adm_del(clientfd,&msg,db);
						break;
					case H:
						adm_amend(clientfd,&msg,db);
						break;
					case I:
						adm_fd(clientfd,&msg,db);
						break;
					case E:
						printf("client offline\n");
						close(clientfd);
					    exit(0);

				}
			}
		}
		else//此为父进程。
		{
			close(clientfd);//父进程不需要连接客户端的clientfd，直接关闭
		}
		
	}
}


/*****************客户端登录函数********************/

/************************************************************************/
/*******************       管理员登录函数       *************************/
/************************************************************************/

void adm_lg(int clientfd,MSG *msg,sqlite3 *db)//管理员登录
{
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	//管理员信息放于adm表
	sprintf(sql,"select * from adm where name='%s' and pwd='%s'",msg->name,msg->pwd);
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		if(n_row==0)//查不到
		{
			strcpy(msg->pwd,"Fail");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			strcpy(msg->pwd,"OK");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
	}
}

/************************************************************************/
/*******************      普通用户登录函数      *************************/
/************************************************************************/

void user_lg(int clientfd,MSG *msg,sqlite3 *db)
{
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	//普通用户登录信息放于user表
	sprintf(sql,"select * from user where name='%s' and pwd='%s'",msg->name,msg->pwd);
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		if(n_row==0)//查不到
		{
			
			strcpy(msg->pwd,"Fail");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			strcpy(msg->pwd,"OK");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
	}
}




/*****************客户端用户二级页面函数********************/

/************************************************************************/
/*******************    普通用户修改密码函数    *************************/
/************************************************************************/

void amend_pswd(int clientfd,MSG *msg,sqlite3 *db)//普通用户修改密码
{
	char sql[M]={0};
	char *errmsg;
	sprintf(sql,"update user set pwd ='%s' where name ='%s' and id = '%d'",msg->pwd,msg->name,msg->id);
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");//注册失败返回给客户端
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		strcpy(msg->pwd,"OK");//注册成功，返回给客户端
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
}

/************************************************************************/
/*******************      普通用户查询函数      *************************/
/************************************************************************/

void user_fd(int clientfd,MSG *msg,sqlite3 *db)//用户查找
{

	
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	//管理员信息放于adm表
	sprintf(sql,"select * from user where name ='%s' and id = '%d'",msg->name,msg->id);
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		if(n_row==0)//查不到
		{
			strcpy(msg->pwd,"Fail");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			strcpy(msg->pwd,"OK");//查询成功，返回给客户端
			strcpy(msg->name,rep[7]);
			strcpy(msg->sex,rep[9]);
			strcpy(msg->age,rep[10]);
			strcpy(msg->salary,rep[11]);
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
	}
}



/*****************客户端管理员二级页面函数********************/

/************************************************************************/
/*******************        添加用户函数        *************************/
/************************************************************************/

void adm_add(int clientfd,MSG *msg,sqlite3 *db)
{
	
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	
	msg->id = num;
	//普通用户登录信息放于user表
	sprintf(sql,"select * from user where name ='%s' and id = '%d'",msg->name,msg->id);
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		if(n_row==0)//查不到
		{
			
			sprintf(sql,"insert into user values('%d','%s','%s','%s','%s','%s')",msg->id,msg->name,msg->pwd,msg->sex,msg->age,msg->salary);
			if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
			{
				printf("%s\n",errmsg);
				strcpy(msg->pwd,"Fail");//注册失败返回给客户端
				send(clientfd,msg,LEN_SMG,0);
				return;
			}
			else
			{	
				num++;
				strcpy(msg->pwd,"OK");//注册成功，返回给客户端
				send(clientfd,msg,LEN_SMG,0);
				return;
			}
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			strcpy(msg->pwd,"Full");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
	}
	
}


/************************************************************************/
/*******************        删除用户函数        *************************/
/************************************************************************/

void adm_del(int clientfd,MSG *msg,sqlite3 *db)
{
	
	char sql[M]={0};
	char *errmsg;
	sprintf(sql,"delete from user where name ='%s' and id = '%d'",msg->name,msg->id);
	if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");//删除失败返回给客户端
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		strcpy(msg->pwd,"OK");//删除成功，返回给客户端
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
}


/************************************************************************/
/*******************        修改用户函数        *************************/
/************************************************************************/

void adm_amend(int clientfd,MSG *msg,sqlite3 *db)
{
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	//普通用户登录信息放于user表
	sprintf(sql,"select * from user where name ='%s' and id = '%d'",msg->name,msg->id);
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		if(n_row==0)//查不到
		{
			strcpy(msg->pwd,"Null");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			char sql[M]={0};
			char *errmsg;
			sprintf(sql,"update user set sex ='%s',age ='%s',salary ='%s' where name ='%s'",msg->sex,msg->age,msg->salary,msg->name);
			if(sqlite3_exec(db,sql,NULL,NULL,&errmsg)!=SQLITE_OK)
			{
				printf("%s\n",errmsg);
				strcpy(msg->pwd,"Fail");//修改失败返回给客户端
				send(clientfd,msg,LEN_SMG,0);
				return;
			}
			else
			{
				strcpy(msg->pwd,"OK");//x成功，返回给客户端
				send(clientfd,msg,LEN_SMG,0);
				return;
			}
		}
	}
	
}

/************************************************************************/
/*******************      管理员查询函数        *************************/
/************************************************************************/
void adm_fd(int clientfd,MSG *msg,sqlite3 *db)
{
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	//管理员信息放于adm表
	sprintf(sql,"select * from user where name ='%s'and id = '%d'",msg->name,msg->id);
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		strcpy(msg->pwd,"Fail");
		send(clientfd,msg,LEN_SMG,0);
		return;
	}
	else
	{
		if(n_row==0)//查不到
		{
			strcpy(msg->pwd,"Fail");
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			strcpy(msg->pwd,"OK");//查询成功，返回给客户端
			strcpy(msg->name,rep[7]);
			strcpy(msg->sex,rep[9]);
			strcpy(msg->age,rep[10]);
			strcpy(msg->salary,rep[11]);
			send(clientfd,msg,LEN_SMG,0);
			return;
		}
	}
}

void max_find(int clientfd,MSG *msg,sqlite3 *db)
{
	int max;
	char sql[M]={0};
	char *errmsg;  //用来存储错误信息字符串 
	char **rep;
	int n_row;  //nRow 查找出的总行数,nColumn 存储列
	int n_column;
	//管理员信息放于adm表
	sprintf(sql,"select max(id) from user");
	if(sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg)!=SQLITE_OK)
	{
		printf("%s\n",errmsg);
		return;
	}
	
	else
	{
		if(n_row==0)//查不到
		{
			num = 0;
			return;
		}
		else  //只要行数大于0，无需打印，直接返回成功
		{
			
			printf("%s\n",rep[1]);
			sscanf(rep[1],"%d",&num);
			num++;
			return;
		}
	}
}

